perm filename TFTP.FAI[S,NET] blob
sn#753309 filedate 1984-05-05 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00009 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 TITLE TFTP - Trivial File Transfer Protocol A B C D X Y Z P IMP FILE PDLEN .IPUDP TFTPRT RRQ WRQ DATA ACK ERROR IBFLEN HSTTAB
C00005 00003 Data area PDL IMPIBF IMPOBF RETOBF DSKIBF DSKOBF STORE SERVER LINBUF MODBUF BLKNUM XSTATS XSTIOS XSTSTB XSTSTT XSTLHS XSTLPR XSTRHS XSTRPR XSTNHS XSTPRO XSTEND UDPBLK UDPSTS UDPLPR UDPHST SRVBLK SRVSTS FNAME FEXT FPPN MODES MODASC MODOCT NMODES MODE
C00008 00004 IMP I/O LOSBIG IMPINI IMPGET CPOPJ1 CPOPJ STRPUT IMPRET IMPOUT TWOBYT SNDERR
C00013 00005 Terminal and disk I/O GETLIN GETLI1 PRSFIL PRSFI1 PRSEXT PRSPRJ PRSPJ1 PRSPRG PRSPG1 PRSMOD PRSMO1 PRSMO2 NXTMOD GOTMOD OPNFIL OPNLKP FILGET FILPUT
C00017 00006 Retrieve DORETR DORET1 DORET2 DORET3 DORET4 DORET5 MAKACK RETEOF RETERR
C00020 00007 Store DOSTOR STBLOK STBYTE STOEOF BLKOUT BLKOU2 BLKOU3 STBLER BLKOU4
C00023 00008 Server startup SSTART SSTAR1 SDONE GETREQ REQBAD GETRE1 GETRE2 GETRE3 NOACK0
C00026 00009 Start here START GETHST WHICH WHICHS WHICHR LCLFIL GTMODE GETRSP GOTRSP BADRSP
C00030 ENDMK
C⊗;
TITLE TFTP - Trivial File Transfer Protocol ;⊗ A B C D X Y Z P IMP FILE PDLEN .IPUDP TFTPRT RRQ WRQ DATA ACK ERROR IBFLEN HSTTAB
COMMENT ⊗
Written by Joe Weening, SU-AI, May 1984.
This is the TFTP User and Server program for WAITS. TFTP is based on
the IP User Datagram Protocol (UDP), and is defined in RFC783.
end of comment ⊗
A←1 ;AC definitions
B←2
C←3
D←4
X←10
Y←11
Z←12
P←17
IMP←←1 ;I/O channels (NETWRK uses 0 for host table)
FILE←←2
PDLEN←←20
.IPUDP←←=17 ;UDP protocol number
TFTPRT←←=69 ;TFTP port
RRQ←←1 ;TFTP opcodes
WRQ←←2
DATA←←3
ACK←←4
ERROR←←5
IBFLEN←←=129 ;IMP buffer length (4 header bytes + 512 data bytes)
HSTTAB←←-1
.INSERT NETWRK.FAI[S,NET] ;Get host table routines
DEFINE FATAL(MESS)<
OUTSTR [ASCIZ/MESS
/]
PUSHJ P,LOSBIG
>;DEFINE FATAL
;Data area ;⊗ PDL IMPIBF IMPOBF RETOBF DSKIBF DSKOBF STORE SERVER LINBUF MODBUF BLKNUM XSTATS XSTIOS XSTSTB XSTSTT XSTLHS XSTLPR XSTRHS XSTRPR XSTNHS XSTPRO XSTEND UDPBLK UDPSTS UDPLPR UDPHST SRVBLK SRVSTS FNAME FEXT FPPN MODES MODASC MODOCT NMODES MODE
PDL: BLOCK PDLEN
IMPIBF: BLOCK 3 ;Buffer headers for IMP
IMPOBF: BLOCK 3
RETOBF: BLOCK 3 ;Copy of IMPOBF block for retransmission
DSKIBF: BLOCK 3 ;Buffer headers for DSK
DSKOBF: BLOCK 3
STORE: BLOCK 1 ; 0 = reading local ← remote
;-1 = storing remote → local
SERVER: BLOCK 1 ;0 if a user, -1 if a server
LINBUF: BLOCK 20 ;Input from terminal, or filename from request
MODBUF: BLOCK 20 ;Transfer mode
BLKNUM: BLOCK 1 ;Current block being transferred
XSTATS: 5 ;IMP MTAPE for status info
XSTEND-. ;Number of words
XSTIOS: BLOCK 1 ;I/O status
XSTSTB: BLOCK 1 ;Status bits
XSTSTT: BLOCK 1 ;State
XSTLHS: BLOCK 1 ;Local host
XSTLPR: BLOCK 1 ;Local port
XSTRHS: BLOCK 1 ;Remote host
XSTRPR: BLOCK 1 ;Remote port
XSTNHS: BLOCK 1 ;Network host
XSTPRO: BLOCK 1 ;Protocol
XSTEND←←.-1
UDPBLK: 26 ;IMP MTAPE for UDP parameters for user
UDPSTS: BLOCK 1 ;Status bits
UDPLPR: BLOCK 1 ;Local port
BLOCK 1
BLOCK 1
TFTPRT ;Remote port
UDPHST: BLOCK 1 ;Remote host
SRVBLK: 26 ;IMP MTAPE for UDP parameters for server
SRVSTS: BLOCK 1 ;Status bits
TFTPRT ;Local port
BLOCK 1
BLOCK 1
0 ;Remote port
0 ;Remote host
FNAME: BLOCK 1
FEXT: BLOCK 1
FPPN: BLOCK 1
MODES: ;Table of mode names
MODASC: POINT 7,[ASCIZ/NETASCII/]
MODOCT: POINT 7,[ASCIZ/OCTET/]
NMODES←←.-MODES
MODE: BLOCK 1 ;Mode we're using
;IMP I/O ;⊗ LOSBIG IMPINI IMPGET CPOPJ1 CPOPJ STRPUT IMPRET IMPOUT TWOBYT SNDERR
;PUSHJ P,LOSBIG on a fatal error, so we can see where we came from.
LOSBIG: HALT .
;This program does a couple of strange things with I/O buffers. Because a DATA
;packet contains more than 128 words, we need to allocate non-standard buffers
;for device IMP. After we output a packet, we may need to retransmit it.
;Therefore we use two output buffers, and BLT the data from the previous buffer
;to the current buffer whenever we decide to retransmit.
IMPINI: INIT IMP,
SIXBIT/IMP/
IMPOBF,,IMPIBF
JRST [FATAL Can't INIT the IMP]
MTAPE IMP,[17 ↔ BYTE(6)0,0,0,0,1,0] ;Set input timeout (2 sec)
MOVEI A,10 ;Set byte size in buffer headers
DPB A,[POINT 6,IMPIBF+1,11]
DPB A,[POINT 6,IMPOBF+1,11]
UINBF IMP,[1 ↔ IBFLEN+1] ;Need only 1 input buffer
UOUTBF IMP,[2 ↔ IBFLEN+1] ;But 2 for output
OUTPUT IMP, ;Set up output buffer header
POPJ P,
;Get data byte from IMP, skip return if successful. Does NOT do an IN UUO.
IMPGET: SOSGE IMPIBF+2
POPJ P,
ILDB A,IMPIBF+1
CPOPJ1: AOS (P)
CPOPJ: POPJ P,
;Macro to write data byte in A to current output packet.
DEFINE IMPPUT<
SOS IMPOBF+2
IDPB A,IMPOBF+1
>;DEFINE IMPPUT
;Put ASCIZ string in current packet (including final null), byte ptr in B.
STRPUT: ILDB A,B
IMPPUT
JUMPN A,STRPUT
POPJ P,
;Retransmit previous packet sent by IMPOUT.
IMPRET: HRLZ A,RETOBF ;Addr of previous buffer
HRR A,IMPOBF ;Addr of current buffer
ADD A,[2,,2] ;BLT pointer for data
HRRZ B,RETOBF
HRRZ B,1(B) ;Data word count in previous buffer
ADDI B,-1(A) ;Final word to copy
BLT A,(B) ;Copy the data
MOVE A,RETOBF+1 ;Old byte ptr
SUB A,RETOBF
ADD A,IMPOBF ;Relocate to new buffer
MOVEM A,IMPOBF+1
MOVE A,RETOBF+2 ;Old count
MOVEM A,IMPOBF+2 ;Copy to buffer header
outstr [asciz/Retransmitting...
/] ;remove after debugging
;fall into IMPOUT
;Output packet in current buffer to IMP, saving info for retransmission.
IMPOUT: MOVE A,[IMPOBF,,RETOBF] ;Copy output buffer header
BLT A,RETOBF+2
SETSTS IMP,0 ;Clear error bits in I/O status
OUT IMP, ;Output the packet
POPJ P,
FATAL IMP output failed
;Get two-byte integer from TFTP packet. (Skips on success, result in A.)
TWOBYT: PUSHJ P,IMPGET ;Get first byte
POPJ P,
MOVEI B,(A)
PUSHJ P,IMPGET ;Get second byte
POPJ P,
LSH B,10
IORI A,(B) ;Combine
JRST CPOPJ1
;Send an error packet. Call:
; PUSHJ P,SNDERR
; <error code>
; <addr of ASCIZ error message>
; <return here>
SNDERR: OUTSTR [ASCIZ/Code to send error packets not written yet. Please send JJW a message
describing what you did to get this error.
/]
AOS (P) ;Just return for now
JRST CPOPJ1
;Terminal and disk I/O ;⊗ GETLIN GETLI1 PRSFIL PRSFI1 PRSEXT PRSPRJ PRSPJ1 PRSPRG PRSPG1 PRSMOD PRSMO1 PRSMO2 NXTMOD GOTMOD OPNFIL OPNLKP FILGET FILPUT
;Get input line from terminal into LINBUF.
GETLIN: MOVE B,[POINT 7,LINBUF]
GETLI1: INCHWL A
CAIN A,15 ;Ignore CR
JRST GETLI1
CAIE A,12 ;Look for activator
CAIN A,175
MOVEI A,0 ;End with a null if found
IDPB A,B
JUMPN A,GETLI1
POPJ P,
;Parse local filename stored in LINBUF. Not very robust yet.
PRSFIL: SETZM FNAME
SETZM FEXT
SETZM FPPN
AOS (P) ;No error returns until this code is improved
MOVE B,[POINT 7,LINBUF]
MOVE C,[POINT 6,FNAME] ;Part we're currently working on
PRSFI1: ILDB A,B
JUMPE A,CPOPJ
CAIN A,"."
JRST PRSEXT
CAIN A,"["
JRST PRSPRJ
CAILE A,140
SUBI A,40 ;Lower → upper
SUBI A,40 ;Make sixbit
IDPB A,C
JRST PRSFI1
PRSEXT: MOVE C,[POINT 6,FEXT]
JRST PRSFI1
PRSPRJ: SETZ C,
PRSPJ1: ILDB A,B
JUMPE A,[HRLZM C,FPPN
POPJ P,]
CAIN A,","
JRST PRSPRG
CAILE A,140
SUBI A,40
LSH C,6
IORI C,-40(A)
JRST PRSPJ1
PRSPRG: HRLZM C,FPPN
SETZ C,
PRSPG1: ILDB A,B
SKIPE A
CAIN A,"]"
JRST [ HRRM C,FPPN
POPJ P,]
CAILE A,140
SUBI A,40
LSH C,6
IORI C,-40(A)
JRST PRSPG1
;Parse mode string pointed to by B.
PRSMOD: PUSH P,B
MOVSI A,-NMODES
PRSMO1: MOVE C,MODES(A)
PRSMO2: ILDB X,B
ILDB Y,C
JUMPE X,[JUMPE Y,GOTMOD
JRST NXTMOD]
JUMPE Y,NXTMOD
CAMN X,Y
JRST PRSMO2
NXTMOD: MOVE B,(P)
AOBJN A,PRSMO1
POP P,B ;No match
POPJ P,
GOTMOD: HRRZM A,MODE
POP P,B
JRST CPOPJ1
;Open file for input or output.
OPNFIL: INIT FILE,
SIXBIT/DSK/
DSKOBF,,DSKIBF
HALT .
MOVE A,MODE
MOVEI B,10
CAIE A,MODOCT-MODES ;If octet mode,
JRST .+3
DPB B,[POINT 6,DSKIBF+1,11] ;Set 8-bit byte size
DPB B,[POINT 6,DSKOBF+1,11]
MOVEI A,FILE
SHOWIT A,
MOVE A,FNAME
MOVE B,FEXT
SETZ C,
MOVE D,FPPN
SKIPE STORE
JRST OPNLKP
ENTER FILE,A
JRST [FATAL ENTER failed]
POPJ P,
OPNLKP: LOOKUP FILE,A
JRST [FATAL LOOKUP failed]
POPJ P,
;Get input byte from file into A.
FILGET: SOSG DSKIBF+2
IN FILE,
JRST [ ILDB A,DSKIBF+1
JRST CPOPJ1] ;Normal return
STATZ FILE,IODEND
POPJ P, ;EOF return
FATAL Disk input error
;Put output byte from A into file.
FILPUT: SOSG DSKOBF+2
OUT FILE,
JRST [ IDPB A,DSKOBF+1
POPJ P,]
FATAL Disk output error
;Retrieve ;⊗ DORETR DORET1 DORET2 DORET3 DORET4 DORET5 MAKACK RETEOF RETERR
;Routine to retrieve a file from the remote host. Call with first data
;packet in input buffer.
DORETR: MOVEI A,1 ;Start at the beginning
MOVEM A,BLKNUM ;This is the first block we want
DORET1: PUSHJ P,TWOBYT ;Get opcode
JRST RETERR
CAIN A,DATA ;Is it data?
JRST DORET2 ;Yes
PUSHJ P,SNDERR ;Send an ERROR packet
4
[ASCIZ/Illegal opcode when DATA expected/]
FATAL Illegal opcode received from remote host
DORET2: PUSHJ P,TWOBYT ;Get block number
JRST RETERR
CAME A,BLKNUM ;Is it the one we want?
JRST [ PUSHJ P,MAKACK ;No, resend ACK they must have missed
JRST DORET4]
AOS BLKNUM
PUSHJ P,MAKACK ;Let our ACK travel while we read the packet
MOVEI C,=512 ;Block size in bytes
DORET3: PUSHJ P,IMPGET ;Get a data byte
JRST RETEOF
PUSHJ P,FILPUT ;Write it out
SOJG C,DORET3 ;Continue until done
DORET4: MOVEI C,10 ;Number of times we'll allow timeout
DORET5: SETSTS IMP,0 ;Clear error bits in I/O status
IN IMP, ;Wait for next DATA block
JRST DORET1 ;Got it, we think
STATO IMP,TMO ;Timeout?
JRST [FATAL IMP input failed]
SOJLE C,[FATAL Timeout]
PUSHJ P,IMPRET ;Retransmit the ACK
JRST DORET5
;Make up and send an ACK for the last block received.
MAKACK: MOVEI A,0 ;First byte of opcode
IMPPUT
MOVEI A,ACK ;Second byte of opcode
IMPPUT
MOVE A,BLKNUM ;Already points to next block
SUBI A,1 ;Make it current block
ROT A,-10 ;High-order byte
IMPPUT
ROT A,10 ;Low-order byte
IMPPUT
JRST IMPOUT ;Send the ACK and return
RETEOF: RELEAS FILE,
PUSHJ P,MAKACK ;Send the final ACK
;We should "dally" here, but we don't for now.
OUTSTR [ASCIZ/File received successfully.
/]
POPJ P,
RETERR: FATAL Error in file retrieve
;Store ;⊗ DOSTOR STBLOK STBYTE STOEOF BLKOUT BLKOU2 BLKOU3 STBLER BLKOU4
;Routine to store a file in the remote host.
DOSTOR: SETZM BLKNUM ;Start at the beginning
STBLOK: MOVEI A,0 ;First byte of opcode
IMPPUT
MOVEI A,DATA ;Second byte of opcode
IMPPUT
AOS A,BLKNUM ;Get next block number
ROT A,-10 ;High-order byte
IMPPUT
ROT A,10 ;Low-order byte
IMPPUT
MOVEI C,=512 ;Block size in bytes
STBYTE: PUSHJ P,FILGET ;Get a byte from the file
JRST STOEOF ;End of file
IMPPUT
SOJG C,STBYTE ;Loop until block full
PUSHJ P,BLKOUT ;Write out the block, wait for ACK
JRST STBLOK ;Continue until done
STOEOF: PUSHJ P,BLKOUT ;Send the last block (even if length 0)
OUTSTR [ASCIZ/File sent successfully.
/]
POPJ P,
;Subroutine to output the block, wait for the ACK, and retransmit if necessary.
BLKOUT: MOVEI C,10 ;Number of times to retransmit
PUSHJ P,IMPOUT ;Send it
BLKOU2: SETSTS IMP,0 ;Clear error bits in I/O status
IN IMP, ;Wait for a response
JRST BLKOU3
STATO IMP,TMO ;Timeout?
JRST [FATAL IMP input failed]
SOJLE C,[FATAL Timeout]
PUSHJ P,IMPRET ;Retransmit
JRST BLKOU2
BLKOU3: PUSHJ P,TWOBYT ;Get opcode
JRST STBLER
CAIN A,ACK
JRST BLKOU4
CAIN A,ERROR
JRST [FATAL Error packet received]
STBLER: FATAL Bad acknowledgement packet
BLKOU4: PUSHJ P,TWOBYT ;Block being ACKed
JRST STBLER
CAME A,BLKNUM ;Is it the block we just sent?
JRST BLKOU2 ;No, ignore and wait some more
POPJ P, ;Yes, return
;Server startup ;⊗ SSTART SSTAR1 SDONE GETREQ REQBAD GETRE1 GETRE2 GETRE3 NOACK0
SSTART: RESET
SETOM SERVER
OUTSTR [ASCIZ/TFTP server starting
/]
MOVE P,[IOWD PDLEN,PDL]
PUSHJ P,IMPINI
MTAPE IMP,SRVBLK ;Set UDP parameters
MTAPE IMP,XSTATS ;Get status info
MOVE A,XSTPRO ;Check our protocol
CAIE A,.IPUDP
HALT .
SSTAR1: SETSTS IMP,0 ;Clear error bits in I/O status
IN IMP, ;Read the request packet
JRST GETREQ
STATZ IMP,TMO
JRST SSTAR1 ;Keep trying
FATAL Input error trying to read request packet
SDONE: RELEAS IMP, ;Server done
EXIT 1, ;Allow continue to restart
JRST SSTART
GETREQ: PUSHJ P,TWOBYT ;Get opcode
JRST REQBAD
CAIE A,RRQ
CAIN A,WRQ
JRST GETRE1 ;It's one we want
REQBAD: PUSHJ P,SNDERR ;Send an ERROR packet
4
[ASCIZ/Bad format request packet/]
JRST SDONE
GETRE1: SETZM STORE ;Assume we're reading
CAIN A,RRQ
SETOM STORE ;No, we're storing
MOVE B,[POINT 7,LINBUF] ;Prepare to read filename
GETRE2: PUSHJ P,IMPGET
JRST REQBAD ;Shouldn't end yet
IDPB A,B
JUMPN A,GETRE2
MOVE B,[POINT 7,MODBUF] ;Prepare to read mode
GETRE3: PUSHJ P,IMPGET
JRST REQBAD
CAIL A,"a" ;Uppercase mode
CAILE A,"z"
CAIA
SUBI A,"a"-"A"
IDPB A,B
JUMPN A,GETRE3
PUSHJ P,PRSFIL ;Parse filename
JRST REQBAD ;Bad filename
MOVE B,[POINT 7,MODBUF]
PUSHJ P,PRSMOD ;Parse mode
JRST REQBAD ;Bad mode
PUSHJ P,OPNFIL ;Open local file
SKIPE STORE ;Are they sending to us?
JRST NOACK0 ;No, no need to ACK
SETZM BLKNUM
PUSHJ P,MAKACK ;Send an ACK of block number 0
SETSTS IMP,0 ;Clear error bits in I/O status
IN IMP, ;Now wait for the first data block
JRST [ PUSHJ P,DORETR
JRST SDONE]
PRINTX Handle input error here
NOACK0: PUSHJ P,DOSTOR
JRST SDONE
;Start here ;⊗ START GETHST WHICH WHICHS WHICHR LCLFIL GTMODE GETRSP GOTRSP BADRSP
JRST SSTART ;Start -1 for server
START: CAI ;No special RPG start
RESET
SETZM SERVER
MOVE P,[IOWD PDLEN,PDL]
PUSHJ P,IMPINI
PUSHJ P,MAPHST
GETHST: OUTSTR [ASCIZ/Remote host? /]
PUSHJ P,GETLIN
MOVE 0,[POINT 7,LINBUF]
PUSHJ P,HSTNAM
JRST [ OUTSTR [ASCIZ/No such host.
/]
JRST GETHST]
JRST [ OUTSTR [ASCIZ/Ambiguous host name.
/]
JRST GETHST]
MOVEM 0,UDPHST
PUSHJ P,UNMHST
SETOM UDPLPR ;Gensym a local port
MTAPE IMP,UDPBLK
SKIPN UDPSTS
JRST WHICH
FATAL Error in system UDP service. Please report this via GRIPE NETWORK.
WHICH: OUTSTR [ASCIZ/Retrieve or store? /]
SETZM STORE
PUSHJ P,GETLIN
LDB A,[POINT 7,LINBUF,6]
CAIE A,"R"
CAIN A,"r"
JRST WHICHR
CAIN A,"S"
CAIN A,"s"
JRST WHICHS
JRST WHICH
WHICHS: SETOM STORE
WHICHR: MOVEI A,0 ;First byte of opcode
IMPPUT
MOVEI A,RRQ ;Second byte of opcode
SKIPE STORE
MOVEI A,WRQ
IMPPUT
OUTSTR [ASCIZ/Remote filename? /]
PUSHJ P,GETLIN
MOVE B,[POINT 7,LINBUF]
PUSHJ P,STRPUT
LCLFIL: OUTSTR [ASCIZ/Local filename? /]
PUSHJ P,GETLIN
PUSHJ P,PRSFIL ;Parse filename
JRST LCLFIL ;Bad filename
GTMODE: OUTSTR [ASCIZ/Ascii or Octet? /]
PUSHJ P,GETLIN
LDB A,[POINT 7,LINBUF,6]
SETZ B,
CAIE A,"A"
CAIN A,"a"
MOVE B,MODASC
CAIE A,"O"
CAIN A,"o"
MOVE B,MODOCT
JUMPE B,GTMODE
PUSH P,B
PUSHJ P,STRPUT ;Tell him the mode
POP P,B
PUSHJ P,PRSMOD
HALT . ;Can't happen?
MOVEI C,10 ;Number of times to retransmit
PUSHJ P,IMPOUT ;Send the request packet
GETRSP: SETSTS IMP,0 ;Clear error bits in I/O status
IN IMP, ;Wait for a response
JRST GOTRSP
STATO IMP,TMO ;Timeout?
JRST [FATAL IMP input failed]
SOJLE C,[FATAL Timeout - no response from host]
PUSHJ P,IMPRET ;Retransmit
JRST GETRSP
GOTRSP: PUSHJ P,OPNFIL ;Open local file
SKIPN STORE ;Storing?
JRST [ PUSHJ P,DORETR ;No, do a retrieve
EXIT]
PUSHJ P,TWOBYT ;Get ACK of packet 0
JRST BADRSP
CAIE A,ACK ;Verify that it really is
JRST BADRSP
PUSHJ P,TWOBYT
JUMPN A,BADRSP
PUSHJ P,DOSTOR ;Store our file
EXIT
BADRSP: FATAL Unexpected response to write request packet
END START